//
//  ChatViewController.swift
//  JKTools
//
//  Created by 姜奎 on 2/19/25.
//

import Cocoa

class ChatViewController: NSViewController {
    @IBOutlet weak var collectionView: NSCollectionView!
    @IBOutlet weak var inputTextView: JKTextView!

    @IBOutlet weak var flowLayout: NSCollectionViewFlowLayout!
    private var observer: NSObjectProtocol?

    var sessionId: String? {
        didSet {
            reloadMessages(by: sessionId)
        }
    }

    var fetchedResultController: NSFetchedResultsController<MessageEntity>? = nil

    func reloadMessages(by seesionId: String?) {
        guard let seesionId = seesionId else { return }

        DispatchQueue.main.async {
            let fetchedResultController = AiStack.shared.messageFetchedResultController(by: seesionId)
            fetchedResultController?.delegate = self
            try? fetchedResultController?.performFetch()
            self.fetchedResultController = fetchedResultController
            self.collectionView.reloadData()
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        setupCollectionView()
        setupNotificationObserver()
    }

    private func setupCollectionView() {
        collectionView.register(UserMessageCell.self, forItemWithIdentifier: UserMessageCell.reuseIdentifier)
        collectionView.register(GuestMessageCell.self, forItemWithIdentifier: GuestMessageCell.reuseIdentifier)
    }

    private func setupNotificationObserver() {

        observer = NotificationCenter.default.addObserver( forName: .didSelectSession, object: nil, queue: .main) { [weak self] notification in

            self?.sessionId = notification.object as? String

        }

        self.inputTextView.addKeyDown { sender, event in
            guard event.keyCode == 36 else {return false }

            self.sendMessage(sender)

            return true
        }

    }

    func sendMessage(_ sender: NSTextView) {
        let message = sender.string.trimmingCharacters(in: .whitespacesAndNewlines)
        sender.string = ""
        guard !message.isEmpty else { return }

        if let sessionId = sessionId {
            let newMessage = Message(id: UUID().uuidString, sessionId: sessionId,content: try! message.dataValue(),
                                     timestamp: Date(),
                                     sender: .user)
            AiStack.shared.insert(MessageEntity.self, datas: [newMessage]) { error in
            }
        } else {
            let session = Session.helloAi()
            let newMessage = Message(id: UUID().uuidString, sessionId: session.id,content: try! message.dataValue(),
                                     timestamp: Date(),
                                     sender: .user)

            AiStack.shared.insert(SessionEntity.self, datas: [session]) { _ in
            }
            AiStack.shared.insert(MessageEntity.self, datas: [newMessage]) { _ in
                self.sessionId = session.id
            }
        }
    }

    private func scrollToBottom() {
        guard let messages = fetchedResultController?.fetchedObjects, messages.count > 0 else { return }

        let lastIndex = IndexPath(item: messages.count - 1, section: 0)

            // ✅ 延迟确保布局完成
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
            self?.collectionView.scrollToItems(at: [lastIndex],
                                               scrollPosition: .bottom)
        }
    }

    private func deleteMessage(with message: MessageEntity) {

        let objectId = message.objectID

        AiStack.shared.delete([objectId]) { _ in
            DispatchQueue.main.async {
                try? self.fetchedResultController?.performFetch()
            }
        }
    }

    override func viewWillLayout() {
        super.viewWillLayout()
        flowLayout.invalidateLayout()
    }

    deinit {
        if let observer = observer {
            NotificationCenter.default.removeObserver(observer)
        }
    }
}

extension ChatViewController: NSWindowDelegate {
    func windowDidResize(_ notification: Notification) {
        if let window = notification.object as? NSWindow {
                // 处理窗口大小变化的逻辑
            print("Window resized to: \(window.frame)")
            flowLayout.invalidateLayout()
        }
    }
}

extension ChatViewController: NSFetchedResultsControllerDelegate {
    func controllerWillChangeContent(_ controller: NSFetchedResultsController<any NSFetchRequestResult>) {

    }

    func controllerDidChangeContent(_ controller: NSFetchedResultsController<any NSFetchRequestResult>) {

    }

    func controller(_ controller: NSFetchedResultsController<any NSFetchRequestResult>, didChange sectionInfo: any NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {

    }

    func controller(_ controller: NSFetchedResultsController<any NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
        switch type {
            case .insert:
                guard let newIndexPath = newIndexPath else { return }

                collectionView.insertItems(at: [newIndexPath])

                collectionView.scrollToItems(at: [newIndexPath], scrollPosition: .bottom)

            case .delete:
                guard let indexPath = indexPath else { return }

                collectionView.deleteItems(at: [indexPath])
            case .move, .update:break
            @unknown default:
                break
        }
    }
}

extension ChatViewController: NSCollectionViewDataSource {
    func collectionView(_ collectionView: NSCollectionView,
                        numberOfItemsInSection section: Int) -> Int {
        fetchedResultController?.fetchedObjects?.count ?? 0
    }

    func collectionView(_ collectionView: NSCollectionView,
                        itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {



        guard let messages = fetchedResultController?.fetchedObjects else { return NSCollectionViewItem() }

        let message = messages[indexPath.item]

        let isOutgoing = message.sender == Message.Sender.user.rawValue

        if isOutgoing {
            let cell = collectionView.makeItem(withIdentifier: UserMessageCell.reuseIdentifier,
                                               for: indexPath) as! UserMessageCell
            cell.configure(with: message)
            return cell
        }

        let cell = collectionView.makeItem(withIdentifier: GuestMessageCell.reuseIdentifier,
                                           for: indexPath) as! GuestMessageCell
        cell.configure(with: message)
        return cell


    }
}

extension ChatViewController: NSCollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: NSCollectionView,
                        layout collectionViewLayout: NSCollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> NSSize {
        guard let messages = fetchedResultController?.fetchedObjects else {
            return .zero
        }

        let message = messages[indexPath.item]

        let size = BubbleSizeCalculator.shared.sizeForMessage(
            message,
            collectionViewWidth: collectionView.bounds.width
        )
        return NSSize(width: collectionView.bounds.width, height: size.height)
    }
}
